package com.devshephard.jucks.SingleDemo.SingleInClazz;


import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * 以懒汉式单例-双重检测锁模式,测试解决一个为单例创建,一个为反射创建所造成的单例模式破坏问题
 */
public class LazyManClazzTest_2 {

    private static volatile LazyManClazzTest_2 lazyManlaDoubleCheck; //加入volatile关键字,防止指令重排的问题

    //单例模式必须构造器私有
    private LazyManClazzTest_2() {

        synchronized (LazyManClazzTest_2.class){
            if( lazyManlaDoubleCheck != null){
                throw new RuntimeException("不要用反射破坏单例");
            }
        }

        //System.out.println(Thread.currentThread().getName() + "ok");  //多线程情况下输出一下当前线程,由于放在了构造器中,如果有多个则表明生成了多个对象

    }

    public static LazyManClazzTest_2 getInstance(){
        if(lazyManlaDoubleCheck == null){ //当lazyMan对象为空,则表明没有生成到内存空间中
            synchronized (LazyManClazzTest_2.class){ //为类加锁,保证多线程下线程安全
                if(lazyManlaDoubleCheck == null){
                    lazyManlaDoubleCheck = new LazyManClazzTest_2();
                }
            }
        }
        return lazyManlaDoubleCheck;
    };

    public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //反射破坏单例模式
        LazyManClazzTest_2 instance1 = LazyManClazzTest_2.getInstance(); //使用单例模式生成对象

        //使用反射生成对象
        Constructor<LazyManClazzTest_2> declaredConstructor = LazyManClazzTest_2.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);
        LazyManClazzTest_2 instance2 = declaredConstructor.newInstance();

        //两个对象的hashCode都不相同,说明单例模式被破坏
        System.out.println(instance1.hashCode());
        System.out.println(instance2.hashCode());
    }

}
